﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using DotNetStar.TheKing.Services;
using SDDP;
using DotNetStar.TheKing.Infrastructure;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Serilog;
namespace DotNetStar.TheKing.Web
{
    using System;
    using DotNetStar.TheKing.Domain.EventHandlers;
    using Filters;
    using Serilog;
    using System.Linq;
    using System.Reflection;
    using DotNetStar.TheKing.Domain;

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDistributedMemoryCache();
            services.AddSession(option=>
            {
                option.Cookie.Name = ".DotNetStar";
            });
            services.AddMemoryCache();
            services.AddLogging(m => m.AddSerilog(dispose: true));
            // Angular's default header name for sending the XSRF token.
            services.AddAntiforgery(options =>
            {
                options.HeaderName = "XSRF-TOKEN";
            });

            Assembly.Load("DotNetStar.TheKing.Services").GetExportedTypes().Where(m => typeof(ServiceBase).IsAssignableFrom(m) && m.BaseType==typeof(ServiceBase))
                .ToList().ForEach(item =>
                {
                    services.AddTransient(item);
                });


            // services.AddSDDPForEntityFrameworkCoreWithTransient<Domain.TheKingDbContext>();
            services.AddDbContext<TheKingDbContext>(m => {
                m.UseSqlServer(this.Configuration.GetConnectionString("DotNetStarConnection"))
                .EnableSensitiveDataLogging();

                });
                       


            Assembly.Load("DotNetStar.TheKing.Domain")
                 .ExportedTypes.Where(m => m.BaseType != null && m.IsClass && m.BaseType.IsGenericType && m.BaseType.GetGenericTypeDefinition() == typeof(EventHandlerBase<>))
                 .ForEach(item => services.AddTransient(item));



            //services.AddSDDPForEFCoreWithTransient();
            services.AddSingleton<NotificationSchedular>();
            services.AddTransient<DbContext, TheKingDbContext>();
            services.AddTransient<IEFCoreDbContext, EFCoreDbContext>();
            services.AddTransient(typeof(IStorage<,>), typeof(EFCoreStorage<,>));

            services.AddSingleton<VerifyCodeService>();
            services.AddSingleton(typeof(IEventBus),factory=>
            {
                var scope = factory.CreateScope();
                
                    return EventBus.Default
                    .Subscribe(scope.ServiceProvider.GetService<UserPointEventHandler>())
                    .Subscribe(scope.ServiceProvider.GetService<UserOperationEventHandler>())
                    .Subscribe(scope.ServiceProvider.GetService<TradingPointTransitionEventHandler>())
                    .Subscribe(scope.ServiceProvider.GetService<NotificationEventHandler>())
                    ;
                
            });

            services.AddMvc(option =>
            {

                //option.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
                // option.Filters.Add(new ExceptionHandlerAttribute());
                // option.Filters.Add(new OwnPageAttribute());
                //var authenticationPolicy = new AuthorizationPolicyBuilder(new[] { CookieAuthenticationDefaults.AuthenticationScheme}).RequireAuthenticatedUser().Build();                
                //option.Filters.Add(new AuthorizeFilter(authenticationPolicy));

            })
            .AddJsonOptions(m => m.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver())
            
            .AddRazorPagesOptions(option =>
            {
                option.Conventions.AllowAnonymousToFolder("/account");
                option.Conventions.AllowAnonymousToFolder("/Content");
                option.Conventions.AuthorizePage("/Content/Edit");
                option.Conventions.AuthorizeFolder("/User/Setting");
                option.Conventions.AddPageRoute("/Content/Detail", "c/{id:int}");
                
            })
            ;

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(option =>
                {
                    option.LoginPath = new PathString("/account/login");
                    option.LogoutPath = new PathString("/account/signout");
                    option.AccessDeniedPath = new PathString("/account/forbidden");
                    option.ClaimsIssuer = "DNS_ISSUER";
                })
                ;
            
        }
        
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseSession();
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
            }
            app.UseAuthentication();
            app.UseStaticFiles();
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                  name: "areas",
                  template: "{area:exists}/{controller=Home}/{action=Login}/{id?}"
                );

                //routes.MapRoute(
                //    name: "content_channel_route",
                //    template: "{c}/{channel}",
                //    defaults:new{ controller="Content",action= "ChannelIndex" });

                //routes.MapRoute(
                //    name: "content_detail_route",
                //    template: "{c}/{id}",
                //    defaults: new { controller = "Content", action = "Detail" });

                //routes.MapRoute(
                //    name: "default",
                //    template: "{controller=Home}/{action=Index}/{id?}");
            });

        }
    }
}
